/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openFuyao is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

// Package config 负责读取和解析配置
package config

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"strings"

	"env-check/pkg/utils"
)

// flagSet 定义命令行参数集合
type flagSet struct {
	configFile   *string
	mode         *string
	logFile      *string
	outputFormat *string
	paths        *string
	pathDeal     *bool
	cleanAuto    *bool
	cleanConfirm *bool
	cleanDryRun  *bool
	programList  *string
}

// LoadConfig 加载配置
func LoadConfig() (*AppConfig, error) {
	// 显示帮助信息
	if hasHelpFlag() {
		showHelp()
		os.Exit(0)
	}

	config := AppConfig{
		OutputFormat: "text",
		LogFile:      "./envCheck.log",
		CleanConfirm: true,
	}

	// 定义并解析命令行参数
	flags, setFlags := defineAndParseFlags()

	// 从配置文件加载（如果指定）
	if *flags.configFile != "" {
		if err := loadConfigFromFile(*flags.configFile, &config); err != nil {
			return nil, fmt.Errorf("load configuration failed: %v", err)
		}
	}

	// 合并命令行参数到配置
	mergeFlagsToConfig(flags, setFlags, &config)

	// 验证配置
	if err := validateConfig(&config); err != nil {
		return nil, err
	}

	return &config, nil
}

// loadConfigFromFile 从文件加载配置
func loadConfigFromFile(filename string, config *AppConfig) error {
	file, err := os.ReadFile(filename)
	if err != nil {
		return err
	}

	return json.Unmarshal(file, config)
}

// parsePathList 解析路径列表字符串
func parsePathList(paths string) []string {
	var result []string
	for _, path := range strings.Split(paths, ",") {
		path = strings.TrimSpace(path)
		if path != "" {
			result = append(result, path)
		}
	}

	return result
}

// validateConfig 验证配置
func validateConfig(config *AppConfig) error {
	validModes := map[OperationMode]bool{
		ModeQuery:        true,
		ModeClean:        true,
		ModeProgramCheck: true,
	}

	if !validModes[config.Mode] {
		return fmt.Errorf("unsupported mode: %s", config.Mode)
	}

	// 对于查询和清理模式，需要路径
	if (config.Mode == ModeQuery || config.Mode == ModeClean) && len(config.Paths) == 0 {
		return fmt.Errorf("at least one path is required")
	}

	// 对于程序检查模式，需要程序列表
	if config.Mode == ModeProgramCheck && len(config.ProgramList) == 0 {
		return fmt.Errorf("program list is required")
	}

	return nil
}

// hasHelpFlag 检查是否有帮助标志
func hasHelpFlag() bool {
	for _, arg := range os.Args[1:] {
		if arg == "-h" || arg == "--help" || arg == "-help" {
			return true
		}
	}
	return false
}

// showHelp 显示详细的帮助信息
func showHelp() {
	fmt.Println("envCheck tool")
	fmt.Println()
	fmt.Println("usage:")
	fmt.Println("  envCheck [options]")
	fmt.Println()
	fmt.Println("base options:")
	fmt.Println("  --config string     config file path (default config.json)")
	fmt.Println("  --mode string       mode: fileQuery, fileClean, programCheck")
	fmt.Println("  --log string        log file path (default envCheck.log)")
	fmt.Println("  --output string     result output format: text, json, csv(default text)")
	fmt.Println("  --paths string      file paths(separated by comma)")
	fmt.Println("  --pathDeal          path pre-deal（expand environment variables and wildcards）")
	fmt.Println()
	fmt.Println("file clean options (--mode=fileClean):")
	fmt.Println("  --cleanAuto              auto clean（no confirmation inquiry）")
	fmt.Println("  --cleanConfirm           confirmation required before cleaning(default true)")
	fmt.Println("  --cleanDryRun            simulate clean")
	fmt.Println()
	fmt.Println("program check options (--mode=programCheck):")
	fmt.Println("  --programList string   need to check application(separated by comma)，for example 'docker,git,python'")
	fmt.Println()
	fmt.Println("examples:")
	fmt.Println("  # Query file information for a given path in the default configuration file")
	fmt.Println("  envCheck --mode=fileQuery")
	fmt.Println()
	fmt.Println("  # Query file information at specified paths")
	fmt.Println(`  envCheck --mode=fileQuery --paths="/tmp,/var/log"`)
	fmt.Println()
	fmt.Println("  # Simulation run before cleanup")
	fmt.Println(`  envCheck --mode=fileClean --paths="/tmp/cache" --cleanDryrun`)
	fmt.Println()
	fmt.Println("  # Check the specified program")
	fmt.Println(`  envCheck --mode=programCheck --programList="docker,kubectl,git"`)
	fmt.Println()
	fmt.Println("  # Use configuration files")
	fmt.Println("  envCheck --config=newConfig.json")
}

// defineAndParseFlags 定义并解析命令行参数
func defineAndParseFlags() (*flagSet, map[string]bool) {
	flags := &flagSet{}

	// 基本参数
	flags.configFile = flag.String("config", "./config.json", "config file path")
	flags.mode = flag.String("mode", "", "mode: fileQuery, fileClean, programCheck")
	flags.logFile = flag.String("log", "", "log file path")
	flags.outputFormat = flag.String("outputFormat", "", "result output format: text, json, csv")
	flags.paths = flag.String("paths", "", "file paths，(separated by comma)")
	flags.pathDeal = flag.Bool("pathDeal", false, "path pre-deal(expand environment variables and wildcards)")

	// 清理参数
	flags.cleanAuto = flag.Bool("cleanAuto", false, "auto clean（no confirmation inquiry）")
	flags.cleanConfirm = flag.Bool("cleanConfirm", true, "confirmation required before cleaning(default true)")
	flags.cleanDryRun = flag.Bool("cleanDryrun", false, "simulate clean")

	// 程序检查参数
	flags.programList = flag.String("programList", "", "need to check application(separated by comma)，for example 'docker,git,python'")

	flag.Parse()

	// 记录哪些标志被显式设置了
	setFlags := make(map[string]bool)
	flag.Visit(func(f *flag.Flag) {
		setFlags[f.Name] = true
	})

	return flags, setFlags
}

// mergeFlagsToConfig 合并命令行参数到配置
func mergeFlagsToConfig(flags *flagSet, setFlags map[string]bool, config *AppConfig) {
	// 字符串类型参数：只有命令行显式设置时才覆盖
	if setFlags["mode"] {
		config.Mode = OperationMode(*flags.mode)
	}
	if setFlags["log"] {
		config.LogFile = *flags.logFile
	}
	if setFlags["outputFormat"] {
		config.OutputFormat = *flags.outputFormat
	}
	if setFlags["paths"] {
		config.Paths = parsePathList(*flags.paths)
	}

	// 布尔类型参数：只有命令行显式设置时才覆盖
	if setFlags["pathDeal"] {
		config.PathsDeal = *flags.pathDeal
	}

	// 路径预处理（根据最终值决定是否执行）
	if config.PathsDeal {
		expander := utils.NewPathExpander()
		dealPaths, _ := expander.ExpandPaths(config.Paths)
		config.Paths = dealPaths
	}

	// 其他布尔参数
	if setFlags["cleanAuto"] {
		config.CleanAuto = *flags.cleanAuto
	}
	if setFlags["cleanConfirm"] {
		config.CleanConfirm = *flags.cleanConfirm
	}
	if setFlags["cleanDryrun"] {
		config.CleanDryRun = *flags.cleanDryRun
	}
	if setFlags["programList"] {
		config.ProgramList = parsePathList(*flags.programList)
	}
}
